/*
 * Copyright (C) 2011, EADS France
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 */

package xowl.generator;

/**
 *
 * @author Laurent WOUTERS
 */
public class PropertyGenerator {
    protected PackageGenerator packageGenerator;
    protected xowl.lang.runtime.Property property;
    protected String propertyName;
    protected ClassGenerator domain;
    protected ClassGenerator rangeClass;
    protected JavaDatatype rangeDatatype;
    protected java.util.List<PropertyGenerator> equivalents;
    protected java.util.List<PropertyGenerator> superProperties;
    protected java.util.List<PropertyGenerator> subProperties;
    protected PropertyGenerator inverse;

    public PackageGenerator getPackage() { return packageGenerator; }
    public xowl.lang.runtime.Property getOWLProperty() { return property; }
    public String getName() { return propertyName; }
    public ClassGenerator getDomain() {
        if (domain != null)
            return domain;
        for (PropertyGenerator sup : superProperties) {
            ClassGenerator supDomain = sup.getDomain();
            if (supDomain != null)
                return supDomain;
        }
        return null;
    }
    public ClassGenerator getRangeClass() {
        if (rangeClass != null)
            return rangeClass;
        for (PropertyGenerator sup : superProperties) {
            ClassGenerator range = sup.getRangeClass();
            if (range != null)
                return range;
        }
        return null;
    }
    public JavaDatatype getRangeDatatype() {
        if (rangeDatatype != null)
            return rangeDatatype;
        for (PropertyGenerator sup : superProperties) {
            JavaDatatype range = sup.getRangeDatatype();
            if (range != null)
                return range;
        }
        return null;
    }
    public java.util.Collection<PropertyGenerator> getEquivalents() { return equivalents; }
    public java.util.Collection<PropertyGenerator> getEquivalencyGroup() {
        java.util.List<PropertyGenerator> group = new java.util.ArrayList<PropertyGenerator>(equivalents);
        group.add(this);
        return group;
    }
    public java.util.List<PropertyGenerator> getDirectSuperProperties() { return superProperties; }
    public java.util.List<PropertyGenerator> getSuperProperties() {
        java.util.List<PropertyGenerator> ancestors = new java.util.ArrayList<PropertyGenerator>(superProperties);
        for (int i=0; i!=ancestors.size(); i++) {
            for (PropertyGenerator ancestor : ancestors.get(i).superProperties) {
                if (!ancestors.contains(ancestor))
                    ancestors.add(ancestor);
            }
        }
        return ancestors;
    }
    public java.util.List<PropertyGenerator> getDirectSubProperties() { return subProperties; }
    public java.util.List<PropertyGenerator> getSubProperties() {
        java.util.List<PropertyGenerator> descendants = new java.util.ArrayList<PropertyGenerator>(subProperties);
        for (int i=0; i!=descendants.size(); i++) {
            for (PropertyGenerator descendant : descendants.get(i).subProperties) {
                if (!descendants.contains(descendant))
                    descendants.add(descendant);
            }
        }
        return descendants;
    }
    public PropertyGenerator getInverse() { return inverse; }
    public boolean isObjectProperty() { return (property instanceof xowl.lang.runtime.ObjectProperty); }
    public boolean isFunctional() {
        Boolean value = property.getIsFunctional();
        if (value == null) return false;
        return value;
    }
    public boolean hasInverse() { return (inverse != null); }
    public boolean isInverseFunctional() {
        Boolean value = ((xowl.lang.runtime.ObjectProperty)property).getIsInverseFunctional();
        if (value == null) return false;
        return value;
    }
    public boolean isSymmetric() {
        Boolean value = ((xowl.lang.runtime.ObjectProperty)property).getIsSymmetric();
        if (value == null) return false;
        return value;
    }
    public boolean isAsymmetric() {
        Boolean value = ((xowl.lang.runtime.ObjectProperty)property).getIsAsymmetric();
        if (value == null) return false;
        return value;
    }
    public boolean isReflexive() {
        Boolean value = ((xowl.lang.runtime.ObjectProperty)property).getIsReflexive();
        if (value == null) return false;
        return value;
    }
    public boolean isIrreflexive() {
        Boolean value = ((xowl.lang.runtime.ObjectProperty)property).getIsIrreflexive();
        if (value == null) return false;
        return value;
    }
    public boolean isTransitive() {
        Boolean value = ((xowl.lang.runtime.ObjectProperty)property).getIsTransitive();
        if (value == null) return false;
        return value;
    }

    public ClassGenerator getClassGenerator(xowl.lang.runtime.Class c) { return packageGenerator.getModel().getClassGenerator(c); }
    public PropertyGenerator getPropertyGenerator(xowl.lang.runtime.Property prop) { return packageGenerator.getModel().getPropertyGenerator(prop); }
    public JavaDatatype getJavaDatatype(xowl.lang.runtime.Datatype datatype) { return packageGenerator.getModel().getJavaDatatype(datatype); }


    public PropertyGenerator(Application app, PackageGenerator pack, xowl.lang.runtime.Property prop) {
        packageGenerator = pack;
        property = prop;
        String iri = property.getInterpretationOf().getHasIRI().getHasValue();
        String[] parts = iri.split("#");
        propertyName = parts[parts.length-1];
        equivalents = new java.util.ArrayList<PropertyGenerator>();
        superProperties = new java.util.ArrayList<PropertyGenerator>();
        subProperties = new java.util.ArrayList<PropertyGenerator>();
    }

    public void buildDomainRange() {
        domain = getClassGenerator(property.getDomain());
        if (domain != null)
            domain.addProperty(this);
        if (isObjectProperty()) {
            rangeClass = getClassGenerator(((xowl.lang.runtime.ObjectProperty)property).getRangeAs(null));
        } else {
            rangeDatatype = getJavaDatatype(((xowl.lang.runtime.DataProperty)property).getRangeAs(null));
        }
    }
    public void buildInverses() {
        if (property instanceof xowl.lang.runtime.ObjectProperty) {
            xowl.lang.runtime.ObjectProperty inv = ((xowl.lang.runtime.ObjectProperty)property).getInverseOf();
            if (inv != null) {
                this.inverse = getPropertyGenerator(inv);
                if (this.inverse != null)
                    this.inverse.inverse = this;
            }
        }
    }
    public void buildEquivalents() {
        for (xowl.lang.runtime.Property eq : property.getAllPropertyEquivalentToAs(null)) {
            PropertyGenerator gen = getPropertyGenerator(eq);
            if (gen != null && !equivalents.contains(gen)) {
                equivalents.add(gen);
                gen.equivalents.add(this);
            }
        }
    }
    public void buildHierarchy() {
        for (xowl.lang.runtime.Property parent : property.getAllSubPropertyOfAs(null)) {
            PropertyGenerator gen = getPropertyGenerator(parent);
            if (gen != null && !superProperties.contains(gen)) {
                superProperties.add(gen);
                gen.subProperties.add(this);
            }
        }
    }
}
